<template>
  <a-form
    :label-col="
      operateOption.labelCol || {
        style: { width: `${operateOption.labelWidth || 120}px` },
      }
    "
    :wrapper-col="operateOption.wrapperCol"
    :labelAlign="operateOption.labelAlign || 'left'"
    :disabled="
      typeof operateOption.disabled === 'function'
        ? operateOption.disabled(modelRef)
        : operateOption.disabled || false
    "
    v-if="loaded"
    :size="operateOption.size"
    :layout="operateOption.layout"
    class="crud-form-container"
  >
    <a-row :gutter="operateOption.gutter || 24" v-if="operateOption.rowNum > 1">
      <template
        v-for="(modelColumnRow, idx) in modelColumnRowNumDisplay"
        :key="idx"
      >
        <template v-for="item in modelColumnRow" :key="item.key">
          <a-col :span="item.span || 12">
            <formItem
              :useFormObj="useFormObj"
              :item="item"
              :modelRef="modelRef"
              :operateOption="operateOption"
            >
              <template v-if="item.formSlot" #[item.formSlot]="scope">
                <slot :name="item.formSlot" v-bind="scope"></slot>
              </template>
            </formItem>
          </a-col>
        </template>
      </template>
    </a-row>
    <template v-else>
      <template v-for="item in modelColumnDisplay" :key="item.key">
        <formItem
          :useFormObj="useFormObj"
          :item="item"
          :modelRef="modelRef"
          :operateOption="operateOption"
        >
          <template v-if="item.formSlot" #[item.formSlot]="scope">
            <slot :name="item.formSlot" v-bind="scope"></slot>
          </template>
        </formItem>
      </template>
    </template>
  </a-form>
</template>
<script setup>
import {
  ref,
  defineProps,
  toRefs,
  defineExpose,
  toRaw,
  reactive,
  nextTick,
  onMounted,
  computed,
  useSlots,
  watchEffect,
} from "vue";
import { Form } from "ant-design-vue";
import { debounce } from "lodash-es";
import { filterOption } from "@/utils/method/index";
import formItem from "@/package/tableCrud/formItem.vue";
const slots = useSlots();
const useForm = Form.useForm;
const emits = defineEmits(["on-submit", "on-cancel", "on-validate-error"]);
const modelRef = ref({});
const modelRules = ref({});
const loaded = ref(false);
const useFormObj = ref({});
const modelColumn = ref([]);
const props = defineProps({
  options: {
    type: Object,
    default: () => {
      return {};
    },
  },
  record: {
    type: Object,
    default: () => {
      return null;
    },
  },
});
const { options, record } = toRefs(props);
const operateOption = ref(options.value);
const refreshOptions = (options, saveData = false) => {
  operateOption.value = options;
  init(saveData);
};

const setCoDicDisabled = (key, value, disabled) => {
  const column = modelColumn.value.find((co) => co.key === key);
  if (column && column.dicData?.length) {
    const dicData = column.dicData.find((dic) => dic.value == value);
    if (dicData) {
      dicData.disabled = disabled;
    }
  }
};

// 设置校验规则
function setRules() {
  const column = toRaw(operateOption.value).column.filter((item) => {
    return item.rules && operateOption.value.type != "detail";
  });
  column.forEach((item) => {
    modelRules.value[item.key] = item.rules;
  });
}

function doCancel() {
  useFormObj.value.resetFields();
  resetForm();
  emits("on-cancel");
}

const doSubmit = debounce(function () {
  useFormObj.value
    .validate(modelColumnDisplay.value.map((item) => item.key))
    .then(async () => {
      const hasLabelInValueColumn = modelColumn.value.filter(
        (item) => item.labelInValue
      );
      const params = {};
      for (let key in toRaw(modelRef.value)) {
        const column = hasLabelInValueColumn.find((col) => col.key == key);
        if (column && column.key === key) {
          params[key] = toRaw(modelRef.value)[key]["value"];
        } else {
          params[key] = toRaw(modelRef.value)[key];
        }
      }

      nextTick(() => {
        console.log("params", params);
        emits("on-submit", params, doCancel);
      });
    })
    .catch((err) => {
      console.error("validate error", err);
      emits("on-validate-error", toRaw(modelRef.value), err);
    });
}, 300);

function resetForm() {
  console.log(modelColumn.value, "modelColumn.value------");
  modelRef.value = (modelColumn.value || []).reduce((acc, cur) => {
    acc[cur.key] = record.value ? record.value[cur.key] : void 0;
    return acc;
  }, {});
  const hasSelectColumn = modelColumn.value.filter((item) => item.select);
  const hasLabelInValueColumn = modelColumn.value.filter(
    (item) => item.labelInValue
  );
  Object.keys(record.value || {}).forEach((keyName) => {
    const value = record.value[keyName];
    if (!modelRef.value.hasOwnProperty(keyName)) {
      modelRef.value[keyName] = value;
    }
    const column = hasSelectColumn.find((item) => item.key === keyName);
    console.log("hasSelectColumn", value, column, keyName);

    if (value && column) {
      const option = column.dicData.find((item) => item.value == value);
      if (column && column.type == "select" && option) {
        column.select(value, option, modelRef);
      } else if (column && column.type == "radio") {
        column.select({ value }, modelRef, setCoDicDisabled);
      }
    }

    const labelInValueColumn = hasLabelInValueColumn.find(
      (item) => item.key === keyName
    );
    if (value && labelInValueColumn) {
      if (labelInValueColumn && labelInValueColumn.type == "select") {
        modelRef.value[keyName] = {
          label: record.value[labelInValueColumn.fieldNames.label],
          value: record.value[labelInValueColumn.fieldNames.value],
        };
      }
    }
  });

  console.log("modelRef", modelRef.value);

  return useFormObj.value.resetFields && useFormObj.value.resetFields();
}
const validate = () => {
  return [
    useFormObj.value.validate(modelColumnDisplay.value.map((item) => item.key)),
    modelRef.value,
  ];
};
const resetFields = () => {
  return [resetForm(), modelRef.value];
};

const init = async (saveData = false) => {
  loaded.value = false;
  modelColumn.value = toRaw(operateOption.value).column;
  console.log("modelColumn.value", toRaw(operateOption.value));
  if (!saveData) {
    await resetForm();
  }
  await setRules();
  useFormObj.value = useForm(modelRef, modelRules.value);
  nextTick(() => {
    loaded.value = true;
  });
};

const showColumnPropMap = {
  form: "display",
  add: "addDisplay",
  edit: "editDisplay",
  detail: "viewDisplay",
};
const editMode = ["form", "add", "edit"];
const modelColumnDisplay = computed(() => {
  return (modelColumn.value || [])
    .filter((item) => {
      if (Object.hasOwnProperty.call(item, "display")) {
        return item.display;
      } else {
        if (
          operateOption.value.type &&
          Object.hasOwnProperty.call(
            item,
            showColumnPropMap[operateOption.value.type]
          )
        ) {
          return item[showColumnPropMap[operateOption.value.type]];
        }
        return item.key !== "action";
      }
    })
    .sort((a, b) => (a.order || 0) - (b.order || 0));
});
// 分组后的布局项
const modelColumnRowNumDisplay = computed(() => {
  const rowNum = operateOption.value.rowNum || 1;
  if (rowNum > 1) {
    const groupColumnList = new Array(
      Math.ceil((modelColumnDisplay.value || []).length / rowNum)
    )
      .fill()
      .map((_) => []);
    groupColumnList.forEach((column, index) => {
      if (column.length < rowNum) {
        column.push(
          ...modelColumnDisplay.value
            .slice(index * rowNum, (index + 1) * rowNum)
            .filter(Boolean)
        );
      }
    });
    return groupColumnList;
  } else {
    return modelColumnDisplay.value;
  }
});
init();

defineExpose({
  doCancel,
  resetForm,
  doSubmit,
  validate,
  resetFields,
  refreshOptions,
});
</script>
<style lang="scss" scoped>
.crud-form-container {
  padding: 24px 16px;
  :deep(.ant-input-number) {
    width: 100%;
  }
}
</style>
